package com.ruoyi.depot.service.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.OrdersProduct;
import com.ruoyi.common.core.domain.ProcuredOrders;
import com.ruoyi.common.enums.InventoryChangeType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.depot.domain.*;
import com.ruoyi.depot.mapper.*;
import com.ruoyi.depot.service.ILocalInventoryReservedLogService;
import com.ruoyi.procured.mapper.ProcuredOrdersMapper;
import com.ruoyi.procured.service.IProcuredOrdersService;
import com.ruoyi.procured.service.impl.PaymentRequestServiceImpl;
import com.ruoyi.walmart.domain.order.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.depot.service.OutboundOrderService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 出库单Service业务层处理
 *
 * @author lxy
 * @date 2025-06-10
 */
@Service
public class OutboundOrderServiceImpl implements OutboundOrderService {
	@Autowired
	private OutboundOrderMapper outboundOrderMapper;
	@Autowired
	private OutboundOrderDetailMapper outboundOrderDetailMapper;
	@Autowired
	private LocalInventoryMapper localInventoryMapper;
	@Autowired
	private LocalInventoryDetailsMapper localInventoryDetailsMapper;
	@Autowired
	private ProcuredOrdersMapper procuredOrdersMapper;
	@Autowired
	private OutboundStockLogMapper outboundStockLogMapper;
	@Autowired
	private InboundStockMapper inboundStockMapper;
	@Autowired
	private ILocalInventoryReservedLogService localInventoryReservedLogService;
	@Autowired
	private OrdersProductMapper ordersProductMapper;
	@Autowired
	private PaymentRequestServiceImpl paymentRequestService;

	/**
	 * 查询出库单
	 *
	 * @param outboundId 出库单主键
	 * @return 出库单
	 */
	@Override
	public OutboundOrder selectOutboundOrderByOutboundId(Long outboundId) {
		return outboundOrderMapper.selectOutboundOrderByOutboundId(outboundId);
	}

	/**
	 * 查询出库单列表
	 *
	 * @param outboundOrder 出库单
	 * @return 出库单
	 */
	@Override
	public List<OutboundOrder> selectOutboundOrderList(OutboundOrder outboundOrder) {
		List<OutboundOrder> outboundOrders = outboundOrderMapper.selectOutboundOrderList(outboundOrder);

		List<Long> outBoundOrdersIds = outboundOrders.stream().map(OutboundOrder::getOutboundId).collect(Collectors.toList());
		if (!outBoundOrdersIds.isEmpty()) {
			// 查询所有的明细记录并根据出库单id进行分组
			Map<Long, List<OutboundOrderDetail>> collect = outboundOrderDetailMapper.selectListDetails(outBoundOrdersIds)
					.stream().collect(Collectors.groupingBy(OutboundOrderDetail::getOutboundId));
			// 分配明细
			for (OutboundOrder order : outboundOrders) {
				order.setDetailList(collect.getOrDefault(order.getOutboundId(), Collections.emptyList()));
			}
		}
		return outboundOrders;
	}

	/**
	 * 新增出库单
	 *
	 * @param outboundOrder 出库单
	 * @return 结果
	 */
	@Override
	public int insertOutboundOrder(OutboundOrder outboundOrder) {
		outboundOrder.setCreateTime(DateUtils.getNowDate());
		return outboundOrderMapper.insertOutboundOrder(outboundOrder);
	}

	/**
	 * 修改出库单
	 *
	 * @param outboundOrder 出库单
	 * @return 结果
	 */
	@Override
	public int updateOutboundOrder(OutboundOrder outboundOrder) {
		outboundOrder.setUpdateTime(DateUtils.getNowDate());
		return outboundOrderMapper.updateOutboundOrder(outboundOrder);
	}

	/**
	 * 批量删除出库单
	 *
	 * @param outboundIds 需要删除的出库单主键
	 * @return 结果
	 */
	@Override
	public int deleteOutboundOrderByOutboundIds(Long[] outboundIds) {
		return outboundOrderMapper.deleteOutboundOrderByOutboundIds(outboundIds);
	}

	/**
	 * 删除出库单信息
	 *
	 * @param outboundId 出库单主键
	 * @return 结果
	 */
	@Override
	public int deleteOutboundOrderByOutboundId(Long outboundId) {
		return outboundOrderMapper.deleteOutboundOrderByOutboundId(outboundId);
	}

	/**
	 * 确认出库
	 *
	 * @param outboundId
	 * @return
	 */
	@Override
	@Transactional
	public int handleConfirmOutbound(Long outboundId) {
		// 查询出库单是否存在
		OutboundOrder outboundOrder = outboundOrderMapper.selectOutboundOrderByOutboundId(outboundId);
		if (outboundOrder == null) {
			throw new ServiceException("出库单不存在，请检查!");
		}
		if (outboundOrder.getStatus() == 1) {
			throw new ServiceException("出库单已出库!");
		}
		// 根据出库单id查询对应的出库明细
		List<OutboundOrderDetail> detailList = outboundOrderDetailMapper.selectList(
				new LambdaQueryWrapper<OutboundOrderDetail>()
						.eq(OutboundOrderDetail::getOutboundId, outboundId)
		);
		// 确认出库说明是采购单处申请过来的，存储的关联单据号就是对应的采购单号
		String procuredOrderNumber = outboundOrder.getRelatedOrderNo();
		// 获取仓库id
		Integer warehouseId = outboundOrder.getWarehouseId();

		// 查询对应的采购订单信息
		ProcuredOrders procuredOrders = procuredOrdersMapper.selectByOrdersNumber(procuredOrderNumber);

		// 扣减库存
		for (OutboundOrderDetail detail : detailList) {
			String sku = detail.getSku(); // sku
			Integer count = detail.getQuantity(); // 出库数量
			Long productId = detail.getProductId();
			if (Objects.equals(outboundOrder.getOutboundType(), Constants.OUTBOUND_TYPE_RETURN)) {
				// 要是为退货出库类型则更新对应采购订单商品明细的待退货数量
				int result = ordersProductMapper.updateByOrdersIdAndReturnPendingQuantity(productId, procuredOrderNumber, count);
				// 再次查询订单商品的待退货量是否为0，如果为0则取消样式
				OrdersProduct ordersProduct = ordersProductMapper.selectOnes(productId, procuredOrderNumber);
				if (ordersProduct.getReturnPendingQuantity() <= 0) {
					// 更新样式
					int update = ordersProductMapper.update(null, new LambdaUpdateWrapper<OrdersProduct>()
							.set(OrdersProduct::getStyleClass, null)
							.eq(OrdersProduct::getId, ordersProduct.getId())
							.eq(OrdersProduct::getDeleteStatus, 0));
					procuredOrdersMapper.updateCancelStyleClass(procuredOrderNumber); // 更新样式并将采购订单状态设置为已完结
					if (update <= 0) {
						throw new ServiceException("更新样式错误");
					}
				}
				if (result <= 0) {
					throw new ServiceException("更新采购订单商品明细待退货量明细失败!");
				}
				int procuredOrderStatus = procuredOrdersMapper.getProcuredOrderStatus(procuredOrders.getOrdersId());
				if(procuredOrderStatus != 3){
					// 要是查询出来的状态不是退货退款中则说明有其他状态在审核中等，就需要更新状态
					paymentRequestService.setProcuredOrderStatus(procuredOrders.getOrdersId());
				}
			} else if (Objects.equals(outboundOrder.getOutboundType(), Constants.OUTBOUND_TYPE_EXCHANGE)) {
				// 修改采购订单商品的相关收货量和待到货量
				// 查询订单商品数据
				OrdersProduct ordersProduct = ordersProductMapper.selectOne(
						new LambdaQueryWrapper<OrdersProduct>()
								.eq(OrdersProduct::getOrdersId, procuredOrders.getOrdersId())
								.eq(OrdersProduct::getProductId, productId)
								.eq(OrdersProduct::getDeleteStatus, 0)
				);
				// 回滚已通知量、未通知量、待到货量
				Long productWaitingStock = ordersProduct.getWaitingStock(); // 待到货量
				Long notifiedCount = ordersProduct.getNotifiedCount(); // 已通知量
				int newWaitingStock = productWaitingStock.intValue() + count; // 回滚后的待到货量
				int newNotifiedCount = notifiedCount.intValue(); // 回滚后的已通知量
				int newUnNotifiedQuantity = newWaitingStock - newNotifiedCount; // 回滚后的未通知量
				long a = ordersProduct.getStorageNumber() - count;

				// 更新订单商品信息
				int update = ordersProductMapper.update(null, new LambdaUpdateWrapper<OrdersProduct>()
						.set(OrdersProduct::getWaitingStock, newWaitingStock)
						.set(OrdersProduct::getNotifiedCount, newNotifiedCount)
						.set(OrdersProduct::getUnnotifiedQuantity, newUnNotifiedQuantity)
						.set(OrdersProduct::getStorageNumber, a)
						.set(OrdersProduct::getDeleteStatus, 0)
						.set(OrdersProduct::getPendingExchangeQuantity, count)
						.eq(OrdersProduct::getId, ordersProduct.getId())
				);
				if (update <= 0) {
					throw new ServiceException("换货更新采购商品信息失败！");
				}
				ProcuredOrders orders = new ProcuredOrders();
				orders.setOrdersId(procuredOrders.getOrdersId());
				orders.setInboundNumber(procuredOrders.getInboundNumber() - count);
				orders.setInboundStatus(procuredOrders.getInboundNumber() - count > 0 ? "2" : "0");
				// 更新采购订单
				procuredOrdersMapper.updateInboundStatus(orders);
			}
			// 扣减对应的库存
			// 1. 查询并加锁，获取库存信息
			LocalInventory inventory = localInventoryMapper.selectBySkuAndWarehouse(sku, warehouseId);

			if (inventory != null) {
				// 2. 使用乐观锁更新库存
				BigDecimal inspectedQty = BigDecimal.valueOf(count);
				BigDecimal previousQty = inventory.getActualQuantity();
				BigDecimal newQty = previousQty.subtract(inspectedQty);

				int rows = localInventoryMapper.updateLocalInventoryBySku(
						sku,
						warehouseId,
						inventory.getVersion(),
						inspectedQty.negate()
				);
				if (rows == 0) {
					// 乐观锁失败，版本不匹配
					throw new ServiceException("库存更新失败，请重试");
				}
				// 获取更新后的库存信息，特别是版本号
				LocalInventory updatedInventory = localInventoryMapper.selectBySkuAndWarehouse(sku, warehouseId);
				BigDecimal reservedQuantity = updatedInventory.getReservedQuantity(); // 旧的库存锁定量
				if (inspectedQty.compareTo(BigDecimal.ZERO) < 0) {
					throw new IllegalArgumentException("出库数量不能为负数");
				}
				BigDecimal subtract = reservedQuantity.subtract(inspectedQty);
				if (subtract.compareTo(BigDecimal.ZERO) < 0) {
					throw new IllegalArgumentException("锁定量不足，出库失败！");
				}

				//新增操作日志
				LocalInventoryReservedLog log = new LocalInventoryReservedLog();
				log.setInventoryReservedLogId(IdUtils.fastSimpleUUID());
				log.setSku(sku);
				log.setWarehouseId(warehouseId.longValue());
				log.setReservedQuantityOld(reservedQuantity);
				log.setReservedQuantityNew(subtract);
				log.setCreatedTime(DateUtils.getNowDate());
				log.setCreatedBy(SecurityUtils.getNickname());
				localInventoryReservedLogService.insertReservedLog(log);

				updatedInventory.setReservedQuantity(subtract);

				// 更新锁定量
				int result = localInventoryMapper.updateReservedQuantity(updatedInventory);
				if (result == 0) {
					// 乐观锁失败，版本不匹配
					throw new ServiceException("库存更新失败，请重试");
				}
				// 选择变动类型
				Integer changeType = null;
				if (outboundOrder.getOutboundType() == 0) {
					changeType = InventoryChangeType.RETURN_OUTBOUND.getCode();
				} else if (outboundOrder.getOutboundType() == 1) {
					changeType = InventoryChangeType.EXCHANGE_OUTBOUND.getCode();
				} else {
					throw new ServiceException("出库类型不匹配，请联系管理员检查");
				}

				// 3. 插入库存变动明细
				insertInventoryDetails(
						inventory.getInventoryId(),
						sku,
						warehouseId.longValue(),
						outboundOrder.getRemark(),
						changeType,
						inspectedQty,
						previousQty,
						newQty,
						outboundOrder.getOutboundNo()
				);

			} else {
				throw new ServiceException("更新的库存信息不存在!");
			}

			// 查询对应的入库日志记录
			InboundStock inboundStock = inboundStockMapper.selectOne(new LambdaQueryWrapper<InboundStock>()
					.eq(InboundStock::getPurchaseOrderId, procuredOrders.getOrdersId())
					.eq(InboundStock::getWarehouseId, warehouseId)
					.eq(InboundStock::getSku, detail.getSku()));
			if (inboundStock == null) {
				throw new ServiceException("该商品不存在对应的入库日志！出库失败！");
			}
			// 更新入库日志表中的剩余库存数量
			int remainingStock = inboundStock.getRemainingQuantity() - detail.getQuantity();
			inboundStockMapper.update(null, new LambdaUpdateWrapper<InboundStock>()
					.set(InboundStock::getRemainingQuantity, remainingStock)
					.eq(InboundStock::getId, inboundStock.getId()));

			// 插入对应的出库日志
			// 计算扣减成本
			BigDecimal quantity = BigDecimal.valueOf(detail.getQuantity()); // 转换出库数量

			BigDecimal totalCost = inboundStock.getUnitCost().multiply(quantity);// 计算出库扣减成本
			OutboundStockLog outboundStockLog = new OutboundStockLog();
			outboundStockLog.setOutboundOrderId(procuredOrders.getOrdersId().toString()); // 关联的单据号（采购订单id）
			outboundStockLog.setBatchId(inboundStock.getId()); // 关联的入库日志id
			outboundStockLog.setSku(detail.getSku()); // sku
			outboundStockLog.setDeductionCost(totalCost); // 扣减成本
			outboundStockLog.setDeductedQuantity(detail.getQuantity()); // 扣减数量
			outboundStockLog.setDeductedDate(new Date()); // 扣减日期
			outboundStockLog.setRemark("采购单号：" + procuredOrderNumber + "退货出库SKU:" + detail.getSku() + "数量：" + quantity + "个。");
			outboundStockLogMapper.insert(outboundStockLog);
		}
		// 修改出库单状态为已出库
		int result = outboundOrderMapper.updateOutboundOrder(OutboundOrder.builder().status(1).outboundId(outboundId).build());
		if (result <= 0) {
			throw new ServiceException("更新出库单状态失败");
		}
//        if(true) throw new ServiceException("=================================================");
		return result;
	}

	// 更新库存变动明细
	private void insertInventoryDetails(
			String inventoryId,
			String sku,
			Long warehouseId,
			String remark,
			int changeType,
			BigDecimal quantity,
			BigDecimal previousQuantity,
			BigDecimal postChangeQuantity,
			String storageNumber
	) {
		// 这里插入库存变动明细
		LocalInventoryDetails details = new LocalInventoryDetails();
		details.setInventoryDetailId(IdUtils.fastSimpleUUID());
		details.setInventoryId(inventoryId);
		details.setSku(sku);
		details.setWarehouseId(warehouseId);
		details.setOperatorName(SecurityUtils.getNickname()); // 设置操作人为当前操作人
		details.setOperatingTime(new Date()); // 操作时间
		details.setChangeType(changeType); // 变动类型为入库
		details.setQuantity(quantity.negate()); // 变动数量
		details.setNotes(remark); // 备注
		details.setPreviousQuantity(previousQuantity); // 变动前的数量
		details.setPostChangeQuantity(postChangeQuantity); // 变动后的数量
		details.setReferenceId(storageNumber); // 关联的入库单
		localInventoryDetailsMapper.insertLocalInventoryDetails(details); // 插入变动记录
	}

	@Override
	public int getUnpairedOutBoundStats() {
		return outboundOrderMapper.getUnpairedOutBoundStats();
	}
}
